-- BineDisplay
-- Created by chengb Apr/19/2015
-- 魔藤外观显示

require "game/ui/module/bine/BineAnimation"

-- BineDisplay继承自Node
BineDisplay = class("BineDisplay", function()
    return cc.Node:create();
end);

function BineDisplay.create(classId, actionType)
    return BineDisplay.new(classId, actionType);
end

-- 构造函数
function BineDisplay:ctor(classId, actionType)
    -- 记录魔藤编号
    self.classId = classId;

    -- 创建主动画
    local animName = BineM.query(classId, "animation");
    local animation = BineAnimation.create(animName .. ".csb");
    animation:setName("animation");
    self.animation = animation;
    self:addChild(animation);
    
    -- 默认为待机动作
    actionType = actionType or BINE_ACTION_IDLE;
    
    local bine;
    if ME.user then
        bine = ME.user.bine;
    end
    
    if bine and bine:isDead() then
        -- 如果已经死亡，跳转至死亡动作最后一帧
        self:gotoDie(true);    
    else
        -- 播放传入的动作
        self:switchAction(actionType);
    end

    self:registerScriptHandler(function(ev)
        if ev == "exit" then
            if self.animation then
                if self.animation.action then
                    self.animation.action:clearFrameEventCallFunc();
                end
                
                self.animation:pause();
                self.animation:destroy();               
                self.animation = nil;
            end
        end
    end);      
end

-- 切换怪物动作
function BineDisplay:switchAction(actionType)
    local ok = true;
    if BINE_ACTION_IDLE == actionType then
        -- 待机
        self:gotoIdle();
    elseif BINE_ACTION_DIE == actionType then
        -- 死亡
        self:gotoDie();
    elseif BINE_ACTION_PRE_CAST == actionType then
        -- 施法前摇
        self:gotoPreCast();
    elseif BINE_ACTION_PRE_ATTACK == actionType then
        -- 攻击前摇
        self:gotoPreAttack();
    else
        -- 暂不支持
        cclog("### 未知的魔藤动作类型：" .. tostring(actionType));
        ok = false;
    end
end

-- 播放待机动作
function BineDisplay:gotoIdle()
    if self.animation == nil then
        return;
    end
    
    local bine;
    if ME.user then
        bine = ME.user.bine;
    end
    
    if bine and bine:isDead() then
        -- 如果已经死亡，跳转至死亡动作
        self:gotoDie(); 
        return;
    end 

    local actionType = BINE_ACTION_IDLE;
    if self.actionType ~= actionType then
        self.actionType = actionType;
    end

    -- 获取帧范围和播放速度
    local frameRange = BineM.query(self.classId, "idle_frame"); 
    local speed = BineM.query(self.classId, "idle_speed");

    -- 播放
    self.animation:play(actionType, true, frameRange[1], frameRange[2], speed);
end

-- 播放施法前摇
function BineDisplay:gotoPreCast()
    if self.animation == nil then
        return;
    end

    local actionType = BINE_ACTION_PRE_CAST;
    if self.actionType ~= actionType then
        self.actionType = actionType;
    end
    
    -- TODO 暂时不播放施法前摇动作，直接抛出施法前摇结束事件
    EventMgr.fire(event.BINE_PRE_CAST_OVER);
    
    --[[
    -- 获取帧范围和播放速度
    local frameRange = BineM.query(self.classId, "pre_cast_frame"); 
    local speed = BineM.query(self.classId, "cast_speed");

    -- 播放
    self.animation:play(actionType, false, frameRange[1], frameRange[2], speed);
    
    -- 注册帧回调函数
    self:registerFrameEvent();
    --]]
end

-- 播放攻击前摇动作
function BineDisplay:gotoPreAttack()
    if self.animation == nil then
        return;
    end

    local actionType = BINE_ACTION_PRE_ATTACK;
    if self.actionType ~= actionType then
        self.actionType = actionType;
    end
    
    -- TODO 暂时不播放攻击前摇动作，直接抛出攻击前摇结束事件，准备播放攻击动作
    EventMgr.fire(event.BINE_PRE_ATTACK_OVER);
    
    --[[
    -- 获取帧范围和播放速度
    local frameRange = BineM.query(self.classId, "pre_attack_frame"); 
    local speed = BineM.query(self.classId, "attack_speed");

    -- 播放
    self.animation:play(actionType, false, frameRange[1], frameRange[2], speed);

    -- 注册帧回调函数
    self:registerFrameEvent();
    --]]
end

-- 播放死亡动作
-- @param toLastFrame : 是否跳转至最后一帧
function BineDisplay:gotoDie(toLastFrame)
    if self.animation == nil then
        return;
    end

    local actionType = BINE_ACTION_DIE;
    if self.actionType ~= actionType then
        self.actionType = actionType;
    end
    
    toLastFrame = toLastFrame or false;
    
    -- 获取帧范围和播放速度
    local frameRange = BineM.query(self.classId, "die_frame"); 
    local speed = BineM.query(self.classId, "die_speed");

    -- 播放
    if toLastFrame then
        self.animation:play(actionType, false, frameRange[2], frameRange[2], speed);
    else
        self.animation:play(actionType, false, frameRange[1], frameRange[2], speed);
    end
end

-- 注册帧回调函数
function BineDisplay:registerFrameEvent()
    -- 移除帧回调处理函数
    self.animation.action:clearFrameEventCallFunc();

    -- 帧回调处理函数
    local function onFrameEvent(frame)
        if nil == frame then
            return;
        end

        -- 使用pilor帧，确保每帧都会有回调过来
        if frame.getEvent and frame:getEvent() == "pilor" then
            -- 帧索引的下标是从0开始的，而配置的下标是从1开始的，故这里要加1
            local frameIndex = frame:getFrameIndex() + 1;
    
            -- 当前帧没有播放完毕
            if not self:isCurrentActionOver(frameIndex) then
                return;
            end
    
            -- 移除帧回调处理函数
            self.animation.action:clearFrameEventCallFunc();
            
            local curActionType = self.actionType;
            
            -- 如果是死亡动作结束，不处理
            if curActionType == BINE_ACTION_DIE then
                return;
            end
            
            if curActionType == BINE_ACTION_PRE_ATTACK then
                -- 如果是攻击前摇结束了，准备播放攻击动作
                EventMgr.fire(event.BINE_PRE_ATTACK_OVER);
            elseif curActionType == BINE_ACTION_PRE_CAST then
                -- 施法前摇结束了，准备播放施法动作
                EventMgr.fire(event.BINE_PRE_CAST_OVER);
            else
                -- 其他情况
                local function callback()
                    -- 切换至待机状态
                    self:gotoIdle();
                end
    
                performWithDelay(self, callback, 0.1);  
            end
        end    
    end

    -- 设置帧回调处理函数
    self.animation.action:setFrameEventCallFunc(onFrameEvent);
end

---------------------------
-- 获取帧范围
-- @param actionType 动作类型
function BineDisplay:getFrameRange(actionType)
    if actionType == BINE_ACTION_IDLE then
        return BineM.query(self.classId, "idle_frame");
    elseif actionType == BINE_ACTION_DIE then
        return BineM.query(self.classId, "die_frame");    
    elseif actionType == BINE_ACTION_PRE_CAST then
        return BineM.query(self.classId, "pre_cast_frame");   
    elseif actionType == BINE_ACTION_PRE_ATTACK then
        return BineM.query(self.classId, "pre_attack_frame");
    else
        trace("BineDisplay", "无法获取帧范围，未知的动作类型：" .. tostring(actionType));
        return nil;             
    end
end

----------------------------
-- 判断当前动作是否已经播完
-- @param curFrameIndex   播放到第几帧
function BineDisplay:isCurrentActionOver(curFrameIndex)
    local curActionType = self.actionType;
    local endIndex = BineM.query(self.classId, "end_frame_index");
    if curFrameIndex >= endIndex then
        -- 已经到最后一帧了
        return true;
    end

    local range = self:getFrameRange(curActionType);
    if not range then
        return false;
    end
    
    -- TODO 兼容最后一帧
    if curFrameIndex >= range[1] and curFrameIndex < range[2] - 1 then
        -- 还没播完
        return false;
    end

    return true;
end






